using System;
using System.Collections.Generic;
using System.Text;

using System.Drawing;
using System.Drawing.Drawing2D;

using System.Windows.Forms;
using Athena.Objects;
using Athena.Core;

namespace Athena.Tools
{
    public class ConnectTool : INonVisualTool
    {

        enum State { Connecting, AddingInput, AddingOutput};

        int _nInputs, _nOutputs; //the number of inputs and outputs to connect
        List<IDrawable> _ItemsToConnect;
        List<Connector> _Connectors;

        private static ConnectTool _oInstance = new ConnectTool();

        public static ConnectTool Instance
        {
            get { return _oInstance; }
        }

        private ConnectTool()
        {
            _Connectors = new List<Connector>();
            _ItemsToConnect = new List<IDrawable>();

            // has items to put into context menu
            _bHasContextMenuItems = true;
            _bHasMenuItems = true;

            ToolManager.Instance.RegisterTool("Connect Tool", "Create a new connection between elements.", this);
 
        }
        
        public override ToolManager.Order Order
        {
            get
            {
                return ToolManager.Order.MIDDLE;
            }
        }

        /// <summary>
        /// Checks whether the following list of items are permitted to be connected
        /// </summary>
        /// <param name="list"></param>
        /// <param name="inputs"></param>
        /// <returns></returns>
        public static string ValidateConnection(List<IDrawable> list, int inputs)
        {
            //two lists -- output nodes need to validate inputs and vice versa
            List<Node> inputNodes = new List<Node>(), outputNodes = new List<Node>();

            int i = 0;
            foreach (IDrawable id in list)  //make a separate lists for input and ouput
            {
                if (id.Item == null)   //cannot connect things without an item
                    return "An item in the reaction is Null";

                if (id.Item is Module)
                    return "Modules cannot be an input or output of a reaction";

                if (i < inputs)
                {
                    if (id.Item is Node)
                        inputNodes.Add(id.Item as Node);
                }
                else
                {
                    if (id.Item is Node)
                        outputNodes.Add(id.Item as Node);
                }
                ++i;
            }
            foreach (Node it in inputNodes) //each input must accept each  output
            {
                if (!it.ValidReactant(inputNodes,outputNodes)) return it.LastErrorMessage;
            }
            foreach (Node it in outputNodes)   //each output must accept each input
            {
                if (!it.ValidProduct(inputNodes, outputNodes)) return it.LastErrorMessage;
            }
            return "";
        }

        ToolStripButton _AddSubstrate = null, _AddProduct = null;

        public override void SetupToolStrip(ToolStrip oToolstrip)
        {
            _oStrip = oToolstrip;

            ToolStripButton _oModify = new ToolStripButton(Utility.GetResource("modif"));// add modifier
            _oModify.ImageScaling = ToolStripItemImageScaling.None;
            _oModify.Click += new EventHandler(_oModify_Click);
            _oModify.ToolTipText = "Add a modifier to a reaction";
            oToolstrip.Items.Add(_oModify);

            oToolstrip.Items.Add("-");

            ToolStripButton _oConnectUniUni = new ToolStripButton(Utility.GetResource("uniuni"));// , "connect 1:1");
            _oConnectUniUni.ImageScaling = ToolStripItemImageScaling.None;
            _oConnectUniUni.Click += new EventHandler(_oConnectUniUni_Click);
            _oConnectUniUni.ToolTipText = "Make a reaction with 1 reactant a 1 product";
            oToolstrip.Items.Add(_oConnectUniUni);

            ToolStripButton _oConnectUniBi = new ToolStripButton(Utility.GetResource("unibi"));//"connect 1:2");
            _oConnectUniBi.ImageScaling = ToolStripItemImageScaling.None;
            _oConnectUniBi.Click += new EventHandler(_oConnectUniBi_Click);
            _oConnectUniBi.ToolTipText = "Make a reaction with 1 reactant a 2 products";
            oToolstrip.Items.Add(_oConnectUniBi);
            

            ToolStripButton _oConnectUniTri = new ToolStripButton(Utility.GetResource("UnTri"));//"connect 1:3");
            _oConnectUniTri.ImageScaling = ToolStripItemImageScaling.None;
            _oConnectUniTri.Click += new EventHandler(_oConnectUniTri_Click);
            _oConnectUniTri.ToolTipText = "Make a reaction with 1 reactant a 3 products";
            oToolstrip.Items.Add(_oConnectUniTri);

            oToolstrip.Items.Add("-");

            ToolStripButton _oConnectBiUni = new ToolStripButton(Utility.GetResource("biuni"));//"connect 2:1");
            _oConnectBiUni.ImageScaling = ToolStripItemImageScaling.None;
            _oConnectBiUni.Click += new EventHandler(_oConnectBiUni_Click);
            _oConnectBiUni.ToolTipText = "Make a reaction with 2 reactants a 1 product";
            oToolstrip.Items.Add(_oConnectBiUni);
            

            ToolStripButton _oConnectBiBi = new ToolStripButton(Utility.GetResource("bibi"));//"connect 2:2");
            _oConnectBiBi.ImageScaling = ToolStripItemImageScaling.None;
            _oConnectBiBi.Click += new EventHandler(_oConnectBiBi_Click);
            _oConnectBiBi.ToolTipText = "Make a reaction with 2 reactants a 2 products";
            oToolstrip.Items.Add(_oConnectBiBi);
            

            ToolStripButton _oConnectBiTri = new ToolStripButton(Utility.GetResource("bitri"));//"connect 2:3");
            _oConnectBiTri.ImageScaling = ToolStripItemImageScaling.None;
            _oConnectBiTri.Click += new EventHandler(_oConnectBiTri_Click);
            _oConnectBiTri.ToolTipText = "Make a reaction with 2 reactants a 3 products";
            oToolstrip.Items.Add(_oConnectBiTri);           


            oToolstrip.Items.Add("-");

            ToolStripButton _oConnectTriUni = new ToolStripButton(Utility.GetResource("TriUni"));//"connect 3:1");
            _oConnectTriUni.ImageScaling = ToolStripItemImageScaling.None;
            _oConnectTriUni.Click += new EventHandler(_oConnectTriUni_Click);
            _oConnectTriUni.ToolTipText = "Make a reaction with 3 reactants a 1 product";
            oToolstrip.Items.Add(_oConnectTriUni);
            

            ToolStripButton _oConnectTriBi = new ToolStripButton(Utility.GetResource("tribi"));//"connect 3:2");
            _oConnectTriBi.ImageScaling = ToolStripItemImageScaling.None;
            _oConnectTriBi.Click += new EventHandler(_oConnectTriBi_Click);
            _oConnectTriBi.ToolTipText = "Make a reaction with 3 reactants a 2 products";
            oToolstrip.Items.Add(_oConnectTriBi);
            

            ToolStripButton _oConnectTriTri = new ToolStripButton(Utility.GetResource("tritri"));//"connect 3:3");
            _oConnectTriTri.ImageScaling = ToolStripItemImageScaling.None;
            _oConnectTriTri.Click += new EventHandler(_oConnectTriTri_Click);
            _oConnectTriTri.ToolTipText = "Make a reaction with 3 reactants a 3 products";
            oToolstrip.Items.Add(_oConnectTriTri);
            

            oToolstrip.Items.Add("-");

            ToolStripButton _oConnectAny = new ToolStripButton(Utility.GetResource("ConnectAny"));// "connect n:m");
            _oConnectAny.ImageScaling = ToolStripItemImageScaling.None;
            _oConnectAny.Click += new EventHandler(_oConnectAny_Click);
            _oConnectAny.ToolTipText = "Make a reaction with X reactants a Y products";
            oToolstrip.Items.Add(_oConnectAny);
            

            oToolstrip.Items.Add("-");

            ToolStripButton _oAddSubstrate = new ToolStripButton(Utility.GetResource("addSubstrate"));// "connect n:m");
            _oAddSubstrate.ImageScaling = ToolStripItemImageScaling.None;
            _oAddSubstrate.Click += new EventHandler(_oAddSubstrate_Click);
            _oAddSubstrate.ToolTipText = "Add new reactants(s) to a reaction";
            oToolstrip.Items.Add(_oAddSubstrate);
            _AddSubstrate = _oAddSubstrate;

            ToolStripButton _oAddProduct = new ToolStripButton(Utility.GetResource("addProduct"));// "connect n:m");
            _oAddProduct.ImageScaling = ToolStripItemImageScaling.None;
            _oAddProduct.Click += new EventHandler(_oAddProduct_Click);
            _oAddProduct.ToolTipText = "Add new products(s) to a reaction";
            oToolstrip.Items.Add(_oAddProduct);
            _AddProduct = _oAddProduct;
        }
        void _oAddSubstrate_Click(object sender, EventArgs e)
        {
            AddInputs();
            UpdateButtons(sender);
        }

        void _oAddProduct_Click(object sender, EventArgs e)
        {
            AddOutputs();
            UpdateButtons(sender);
        }


        void InsertCurve(int inputs, int outputs)
        {
            IsActive = true;
            Connect(inputs, outputs);
        }

        static FormConnect _oFormConnect = new FormConnect();

        void _oConnectAny_Click(object sender, EventArgs e)
        {
            Reset();
            UpdateButtons(sender);
            if (_oFormConnect.ShowDialog() == DialogResult.OK)
            {
                InsertCurve(_oFormConnect.Inputs, _oFormConnect.Outputs);
            }
        }

        void _oConnectTriTri_Click(object sender, EventArgs e)
        {
            InsertCurve(3, 3);
            UpdateButtons(sender);
        }

        void _oConnectTriBi_Click(object sender, EventArgs e)
        {
            InsertCurve(3, 2);
            UpdateButtons(sender);
        }

        void _oConnectTriUni_Click(object sender, EventArgs e)
        {
            InsertCurve(3, 1);
            UncheckAllButtons();
            UpdateButtons(sender);
        }
        void _oConnectBiTri_Click(object sender, EventArgs e)
        {
            InsertCurve(2, 3);
            UpdateButtons(sender);
        }

        void _oConnectBiBi_Click(object sender, EventArgs e)
        {
            InsertCurve(2, 2);
            UpdateButtons(sender);
        }

        void _oModify_Click(object sender, EventArgs e)
        {
            InsertCurve(1, 1);
            UpdateButtons(sender);
        }

        private void UpdateButtons(object sender)
        {
            if (sender is ToolStripButton)
            {
                ToolStripButton toolStripButton = (ToolStripButton)sender;
                UncheckAllButtons(toolStripButton);
                Utility.MouseImage = toolStripButton.Image;
            }
        }
        void _oConnectBiUni_Click(object sender, EventArgs e)
        {
            InsertCurve(2, 1);

            UpdateButtons(sender);
        }

        void _oConnectUniTri_Click(object sender, EventArgs e)
        {
            InsertCurve(1, 3);
            UpdateButtons(sender);
        }

        void _oConnectUniBi_Click(object sender, EventArgs e)
        {
            InsertCurve(1, 2);
            UpdateButtons(sender);
        }

        void _oConnectUniUni_Click(object sender, EventArgs e)
        {
            InsertCurve(1, 1);
            UpdateButtons(sender);
        }

        State CurrentState;
        /// <summary>
        /// Connects one of more input IGlyphs to one or more output IGlyphs
        /// The tools deactivated if the number of inputs/outputs are < 1
        /// </summary>
        /// <param name="numInputs"></param>
        /// <param name="numOutputs"></param>
        public void Connect(int numInputs, int numOutputs)
        {
            CurrentModel.DeselectItems();
            Utility.Refresh();
            Reset();
            _nInputs = numInputs;
            _nOutputs = numOutputs;
            CurrentState = State.Connecting;
        }

        public void AddInputs()
        {
            IsActive = true;
            Reset();
            CurrentState = State.AddingInput;
        }

        public void AddOutputs()
        {
            IsActive = true;
            Reset();
            CurrentState = State.AddingOutput;
        }


        private void Reset()
        {
            foreach (IDrawable ig in _ItemsToConnect)
                ig.IsSelected = false;

            foreach (Connector bc in _Connectors)
                bc.IsSelected = false;

            _ItemsToConnect.Clear();
            _Connectors.Clear();
        }
        /*
        /// <summary>
        /// A regulation reaction can only have one output
        /// A reaction cannot be regulation and reaction at the same time
        /// </summary>
        private void Validate()
        {
            List<IDrawable> items = new List<IDrawable>(), inputs = new List<IDrawable>();

            for (int i = 0; i < _ItemsToConnect.Count; ++i)
                if (i < _nInputs)
                    inputs.Add(_ItemsToConnect[i]);
                else
                    items.Add(_ItemsToConnect[i]);

            bool regulation = false;
            bool reaction = false;
            foreach (IDrawable id in items)
            {
                if (id.Item is Core.Edge || id.Item is Core.Part)
                {
                    regulation = true;                    
                }
                if (id.Item is Species)
                {
                    reaction = true;
                }
            }
            if (regulation && reaction)
            {
                foreach (IDrawable id in items)
                {                    
                    if (id == null || id.Item is Edge || id.Item is Part)
                        _ItemsToConnect.Remove(id);
                }
            }
            if (regulation && items.Count > 1)
            {
                _ItemsToConnect.Clear();
                _ItemsToConnect.AddRange(inputs);
                _ItemsToConnect.Add(items[0]);
            }
        }*/

        /// <summary>
        /// Constructs the reactions from _ItemsToConnect list
        /// If Parts are outputs, then each input will be separately connected to the output
        /// </summary>
        void MakeReactions()
        {
            if (_ItemsToConnect == null || _ItemsToConnect.Count == 0) return;

            List<IDrawable> regulatedParts = new List<IDrawable>();

            int i = 0;
            foreach (IDrawable id in _ItemsToConnect)
            {
                if (i >= _nInputs && id.Item is Part)
                    regulatedParts.Add(id);
                ++i;
            }

            if (regulatedParts.Count == 0)
            {
                BezierConnector bz = new BezierConnector(_ItemsToConnect, _nInputs);
                CurrentModel.AddToModel(bz, false); //connect points
            }
            else
            {
                foreach (IDrawable id in _ItemsToConnect)
                {
                    if (!regulatedParts.Contains(id))
                    {
                        foreach (IDrawable target in regulatedParts)
                        {
                            BezierConnector bz = new BezierConnector(id, target);
                            CurrentModel.AddToModel(bz, false); //connect points
                        }
                    }
                }
            }
        }

        /// <summary>
        /// The reaction is made at mouse-up, so this is the main event
        /// </summary>
        /// <param name="e"></param>
        public override void OnMouseUp(HandledMouseEventArgs e)
        {
            if (!IsActive) return;
            PointF location = Utility.GetTransformedPoint(e.Location);
            try
            {
                switch (CurrentState)
                {
                    case State.Connecting:
                        if (_ItemsToConnect.Count > 0 && _ItemsToConnect.Count + _Connectors.Count >= _nInputs + _nOutputs)
                        {
                            //Validate();
                            if (_nInputs > _ItemsToConnect.Count) _nInputs = _ItemsToConnect.Count;
                            if (_Connectors.Count > 0)
                            {
                                HistoryManager.History.SetControllPoint("Added new Modifiers");
                                foreach (Connector c in _Connectors)
                                    foreach (IDrawable id in _ItemsToConnect)
                                    {
                                        c.AddModifier(id);
                                    }
                            }
                            else
                            {
                                string error = ValidateConnection(_ItemsToConnect, _nInputs);
                                if (string.IsNullOrEmpty(error))
                                {
                                    HistoryManager.History.SetControllPoint("Made new Reaction");
                                    MakeReactions();
                                }
                                else
                                {
                                    Utility.SetMessage("ConnectTool: " + error);
                                }
                            }
                            Reset();
                            CurrentModel.OnModelChanged(EventArgs.Empty);
                            Utility.Refresh();
                            e.Handled = true;
                        }
                        break;
                    case State.AddingInput:
                        if (_Connectors.Count > 0 && _ItemsToConnect.Count > 0)
                        {
                            //Validate();
                            HistoryManager.History.SetControllPoint("Added Substrate");
                            foreach (IDrawable id in _ItemsToConnect)
                                foreach (Connector bc in _Connectors)
                                {
                                    List<IDrawable> list = bc.Nodes;  //make a list with this new item 
                                    list.Insert(0, id);
                                    string error = ValidateConnection(list, bc.ReactantCount + 1);
                                    if (string.IsNullOrEmpty(error)) //check whether it is valid
                                    {
                                        bc.AddReactant(id);  //make the connection
                                    }
                                    else
                                    {
                                        Utility.SetMessage("ConnectTool: " + error);
                                    }
                                }
                            CurrentModel.OnModelChanged(EventArgs.Empty);
                            Reset();
                            Utility.Refresh();
                            e.Handled = true;
                        }
                        break;
                    case State.AddingOutput:
                        if (_Connectors.Count > 0 && _ItemsToConnect.Count > 0)
                        {
                            //Validate();
                            HistoryManager.History.SetControllPoint("Added Product");
                            foreach (IDrawable id in _ItemsToConnect)
                                foreach (Connector bc in _Connectors)
                                {
                                    List<IDrawable> list = bc.Nodes;  //make a list with this new item 
                                    list.Add(id);
                                    string error = ValidateConnection(list, bc.ReactantCount + 1);
                                    if (string.IsNullOrEmpty(error)) //check whether it is valid
                                    {
                                        bc.AddProduct(id);
                                    }
                                    else
                                    {
                                        Utility.SetMessage("ConnectTool: " + error);
                                    }
                                }
                            Reset();
                            CurrentModel.OnModelChanged(EventArgs.Empty);
                            Utility.Refresh();
                            e.Handled = true;
                        }
                        break;
                    
                    default:
                        break;
                }
            }
            catch (Exception) { Reset(); }
        }

        public override void OnMouseDown(HandledMouseEventArgs e)
        {            
            if (!IsActive) return;

            PointF location = Utility.GetTransformedPoint(e.Location);
            List<IDrawable> oItems = CurrentModel.FindItems(location);

            if (oItems.Count < 1)    //if no items selected, deactivate
            {
                //IsActive = false;
                Reset();
                return;
            }

            if ((CurrentState == State.AddingInput || CurrentState == State.AddingOutput || 
                 CurrentState == State.Connecting) && 
                oItems[oItems.Count - 1] is Connector)   //if a connector is selected, add it to the list of connectors
            {
                if (!_Connectors.Contains((Connector)oItems[oItems.Count - 1])) //cant select a connector twice
                {
                    oItems[oItems.Count - 1].IsSelected = true;
                    _Connectors.Add((Connector)(oItems[oItems.Count - 1]));
                    e.Handled = true;
                }
            }
            else
            if (oItems[oItems.Count - 1] != null)   //get the first item only
            {
                _ItemsToConnect.Add(oItems[oItems.Count - 1]); //add it to the list of items to connect
                oItems[oItems.Count - 1].IsSelected = true;
                e.Handled = true;
            }
        }

        public override void OnKeyDown(KeyEventArgs args)
        {
            switch (args.KeyCode)
            {
                case Keys.Return:
                    HistoryManager.History.SetControllPoint("Make Pretty");
                    foreach (IDrawable id in CurrentModel.Selected)
                    {
                        if (id is Connector)
                        {
                            (id as Connector).MakePretty();
                            
                        }
                    }
                    Utility.Refresh();
                    break;
                case Keys.Delete:
                    HistoryManager.History.SetControllPoint("Delete Selected Curve");
                    foreach (IDrawable id in CurrentModel.Selected)
                    {
                        if (id is BezierConnector && ((BezierConnector)id).RemoveSelectedCurves())
                            args.Handled = true;
                    }
                    Utility.Refresh();
                    break;

                default:
                    break;
            }
        }

        public override void OnKeyUp(KeyEventArgs args)
        {

        }

        /// <summary>
        /// called when tool is activated
        /// </summary>
        public override void OnActivate()
        {
            Reset();
        }

        /// <summary>
        /// Called when Tool is deactivated
        /// </summary>
        public override void OnDeactivate()
        {
            Reset();
            UncheckAllButtons();
        }
               

        public override void OnSelectionChanged()
        {

        }

        public override void SetupContextMenu(ToolStripMenuItem oStrip)
        {
            ToolCommand[] commands = GetDynamicCommandsArray();
            foreach (ToolCommand command in commands)
            {
                if (command != null)
                    oStrip.DropDownItems.Add(command.ToMenuItem());
            }
        }
        public override bool Handles(List<Type> oTypes)
        {
            bool bResult = true;
            foreach (Type t in oTypes)
            {
                bResult &= Handles(t);
                if (!bResult) return false;
            }
            return bResult;
        }

        private bool Handles(Type t)
        {
            return Utility.IsTypeNoAbstract(typeof(Athena.Objects.Connector), t);
        }

        class ToolCommand
        {
            private string _sCommand;

            public string Command
            {
                get { return _sCommand; }
                set { _sCommand = value; }
            }

            private Bitmap _Icon;
            public Bitmap Icon
            {
                get
                {
                    return _Icon;
                }
                set
                {
                    _Icon = value;
                }
            }

            private string _Description;
            public string Description
            {
                get
                {
                    return _Description;
                }
                set
                {
                    _Description = value;
                }
            }


            public ToolCommand()
            {
                _sCommand = null;
                _Icon = null;
            }

            /// <summary>
            /// Initializes a new instance of the ToolCommand class.
            /// </summary>
            /// <param name="sCommand"></param>
            /// <param name="icon"></param>
            /// <param name="description"></param>
            public ToolCommand(string sCommand, Bitmap icon, string description)
            {
                _sCommand = sCommand;
                _Icon = icon;
                _Description = description;
            }

            public ToolStripItem ToMenuItem()
            {
                if (_Icon == null && _sCommand == null)
                {
                    return new ToolStripSeparator();
                }
                else
                {

                    ToolStripMenuItem oItem = new ToolStripMenuItem(_sCommand);
                    if (_Icon != null)
                        oItem.Image = _Icon;
                    oItem.Tag = _sCommand;
                    oItem.ToolTipText = _Description;
                    oItem.ImageScaling = ToolStripItemImageScaling.None;
                    oItem.Click += new EventHandler(CommandExecute);
                    return oItem;
                }
            }

            public ToolStripItem ToToolStripButton()
            {
                if (_Icon == null)
                {
                    return new ToolStripSeparator();
                }
                else
                {
                    ToolStripButton oButton = new ToolStripButton(_sCommand);
                    if (_Icon != null)
                        oButton.Image = _Icon;
                    oButton.Checked = true;
                    oButton.DisplayStyle = ToolStripItemDisplayStyle.Image;
                    oButton.Tag = _sCommand;
                    oButton.ImageScaling = ToolStripItemImageScaling.None;
                    oButton.ToolTipText = _Description;
                    oButton.Click += new EventHandler(CommandExecute);
                    return oButton;
                }
            }

            void CommandExecute(object sender, EventArgs e)
            {
                string sTag = "";
                if (sender is ToolStripButton)
                    sTag = (string)((ToolStripButton)sender).Tag;
                else if (sender is ToolStripMenuItem)
                    sTag = (string)((ToolStripMenuItem)sender).Tag;
                else
                    return;

                //since all are connectors, the following methods can be applied
                switch (sTag)
                {
                    case "Insert New Point":
                        foreach (IDrawable id in CurrentModel.Selected)
                        {
                            if (id is BezierConnector)
                                ((BezierConnector)id).InsertLineBreaks = true;
                        }
                        Utility.Refresh();
                        break;
                    case "Link Overlapping Points":
                        foreach (IDrawable id in CurrentModel.Selected)
                        {
                            if (id is BezierConnector) 
                                ((BezierConnector)id).LinkControlPoints = true;
                        }
                        break;
                    case "Separate Linked Points":
                        foreach (IDrawable id in CurrentModel.Selected)
                        {
                            if (id is BezierConnector) 
                                ((BezierConnector)id).LinkControlPoints = false;
                        }
                        break;
                    case "Straight Lines":
                        foreach (IDrawable id in CurrentModel.Selected)
                        {
                            if (id is BezierConnector) 
                                ((BezierConnector)id).StraightLines = true;
                        }
                        Utility.Refresh();
                        break;
                    case "Bezier Curves":
                        foreach (IDrawable id in CurrentModel.Selected)
                        {
                            if (id is BezierConnector) 
                                ((BezierConnector)id).StraightLines = false;
                        }
                        Utility.Refresh();
                        break;
                    case "Add Substrate(s)":
                        _oInstance.AddInputs();
                        foreach (IDrawable id in CurrentModel.Selected)
                        {
                            if (id is BezierConnector) 
                                _oInstance._Connectors.Add((BezierConnector)id);
                        }
                        _oInstance.UpdateButtons(_oInstance._AddSubstrate);
                        Utility.Refresh();
                        break;
                    case "Add Product(s)":
                        _oInstance.AddOutputs();
                        foreach (IDrawable id in CurrentModel.Selected)
                        {
                            if (id is BezierConnector) 
                                _oInstance._Connectors.Add((BezierConnector)id);
                        }
                        _oInstance.UpdateButtons(_oInstance._AddProduct);
                        Utility.Refresh();
                        break;
                    case "Remove Segment":
                        foreach (IDrawable id in CurrentModel.Selected)
                        {
                            if (id is BezierConnector) 
                                ((BezierConnector)id).RemoveSelectedCurves();
                        }
                        Utility.Refresh();
                        break;
                    case "Show Middle Segment":
                        _oInstance.AddOutputs();
                        foreach (IDrawable id in CurrentModel.Selected)
                        {
                            if (id is BezierConnector) 
                                ((BezierConnector)id).ShowMiddleSegment = true;
                        }
                        Utility.Refresh();
                        break;
                    case "Hide Middle Segment":
                        _oInstance.AddOutputs();
                        foreach (IDrawable id in CurrentModel.Selected)
                        {
                            if (id is BezierConnector) 
                                ((BezierConnector)id).ShowMiddleSegment = false;
                        }
                        Utility.Refresh();
                        break;
                    case "Make Pretty":                        
                        foreach (IDrawable id in CurrentModel.Selected)
                        {
                            if (id is BezierConnector) 
                                ((BezierConnector)id).MakePretty();
                        }
                        Utility.Refresh();
                        break;
                    case "Disconnect item":   //removes all links, including Parts connected to each other
                        HistoryManager.History.SetControllPoint("Disconnect all connections");
                        if (CurrentModel.Selected.Count > 0)
                        {
                            foreach (IDrawable id in CurrentModel.Selected)
                            {
                                if (id is IGlyph)
                                {
                                    List<Connector> inputs = ((IGlyph)id).IncomingConnections,
                                                    outputs = ((IGlyph)id).OutgoingConnections;

                                    for (int i =0; i < inputs.Count; ++i)
                                    {
                                        inputs[i].RemoveNode(id);
                                    }
                                    for (int i = 0; i < outputs.Count; ++i)
                                    {
                                        outputs[i].RemoveNode(id);
                                    }
                                        
                                    if (id is PartGlyph)   //if part
                                    {
                                        if (((PartGlyph)id).Right == null && ((PartGlyph)id).Left == null)
                                            id.Parent = null;
                                        else
                                        {
                                            ((PartGlyph)id).Right = null;   //disconnect
                                            ((PartGlyph)id).Left = null;
                                        }
                                    }
                                }
                            }
                        }
                        Utility.Refresh();
                        break;
                    default:
                        break;
                }
            }


        }

        private ToolCommand[] GetDynamicCommandsArray()
        {
            if (CurrentModel.Selected[0] is IGlyph)
            {
                ToolCommand[] array = new ToolCommand[1];
                array[0] = _oCommands[0];
                return array;
            }
            else
            {
                ToolCommand[] array = new ToolCommand[10];
                for (int i = 0, j = 1; i < 10 && j < _oCommands.Length; ++i, ++j)
                {
                    switch (j)
                    {
                        case 2:
                            if (CurrentModel.Selected[0] is BezierConnector)
                            {
                                if (((BezierConnector)CurrentModel.Selected[0]).ShowMiddleSegment)
                                {
                                    array[i] = _oCommands[j + 1];
                                }
                                else
                                {
                                    array[i] = _oCommands[j];
                                }
                                ++j;
                            }
                            break;
                        case 4:
                            if (CurrentModel.Selected[0] is BezierConnector)
                            {
                                if (((BezierConnector)CurrentModel.Selected[0]).LinkControlPoints)
                                {
                                    array[i] = _oCommands[j + 1];
                                }
                                else
                                {
                                    array[i] = _oCommands[j];
                                }
                                ++j;
                            }
                            break;
                        case 7:
                            if (CurrentModel.Selected[0] is BezierConnector)
                            {
                                if (!((BezierConnector)CurrentModel.Selected[0]).StraightLines)
                                {
                                    array[i] = _oCommands[j + 1];
                                }
                                else
                                {
                                    array[i] = _oCommands[j];
                                }
                                ++j;
                            }
                            break;
                        default:
                            array[i] = _oCommands[j];
                            break;
                    }
                }
                return array;
            }
        }

        static ToolCommand[] _oCommands = new ToolCommand[]
        {
            new ToolCommand("Disconnect item", null , "Remove all connections to and from this item"),
            new ToolCommand("Insert New Point", null , "Insert a new control point at the selected location"),
            new ToolCommand("Show Middle Segment", null , "Show the middle segment"),
            new ToolCommand("Hide Middle Segment", null , "Hide the middle segment"),
            new ToolCommand("Link Overlapping Points", null , "Link all overlapping control points"),
            new ToolCommand("Separate Linked Points", null , "Unlink all overlapping control points"),
            new ToolCommand(), 
            new ToolCommand("Bezier Curves", null , "Change to bezier mode"),
            new ToolCommand("Straight Lines", null , "Change to linear mode"),
            new ToolCommand(), 
            new ToolCommand("Add Substrate(s)", global::Athena.Properties.Resources.addSubstrate, "Add more substrate(s)"),
            new ToolCommand("Add Product(s)", global::Athena.Properties.Resources.addProduct, "Add more products"),
            new ToolCommand("Remove Segment", null , "Remove the selected connection(s)"),
            new ToolCommand("Make Pretty", null , "Make the curves clean")
            
        };


    }
}
